﻿using System;
using System.Collections.Generic;

// 客户改变主意
class CustomerChangedMindException : Exception
{
    public CustomerChangedMindException(string message) : base(message) { }
}

// 网络故障
class NetworkFailureException : Exception
{
    public NetworkFailureException(string message) : base(message) { }
}

// 大额取款
class LargeWithdrawalArgs : EventArgs
{
    public Account Account { get; }
    public decimal Amount { get; }

    public LargeWithdrawalArgs(Account account, decimal amount)
    {
        Account = account;
        Amount = amount;
    }
}
enum AccountType
{
    Savings,
    Checking
}

class Account
{
    private string _accountNumber;
    private decimal _balance;

    public string AccountNumber
    {
        get => _accountNumber;
        private set => _accountNumber = value;
    }

    public decimal Balance
    {
        get => _balance;
        protected set => _balance = value;
    }

    public Account(string accountNumber, decimal initialBalance)
    {
        AccountNumber = accountNumber;
        Balance = initialBalance;
    }
    //存款
    public virtual void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Deposit amount must be positive.");
        Balance += amount;
        Console.WriteLine($"Deposited {amount:C} to account {AccountNumber}. New balance: {Balance:C}");
    }

    // 取款
    public virtual void Withdraw(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Withdrawal amount must be positive.");
        if (amount > Balance)
            throw new InvalidOperationException("Insufficient balance.");
        Balance -= amount;
        Console.WriteLine($"Withdrew {amount:C} from account {AccountNumber}. New balance: {Balance:C}");
    }
}

// 储蓄账户
class SavingsAccount : Account
{
    public SavingsAccount(string accountNumber, decimal initialBalance)
        : base(accountNumber, initialBalance) { }
}

// 支票账户
class CheckingAccount : Account
{
    private const decimal OverdraftLimit = 1000m; // 透支限额 1000 元

    public CheckingAccount(string accountNumber, decimal initialBalance)
        : base(accountNumber, initialBalance) { }

    // 支持透支
    public override void Withdraw(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Withdrawal amount must be positive.");
        if (amount > Balance + OverdraftLimit)
            throw new InvalidOperationException("Exceeds overdraft limit.");
        Balance -= amount;
        Console.WriteLine($"Withdrew {amount:C} from checking account {AccountNumber}. New balance: {Balance:C}");
    }
}

// ATM 类
class ATM
{
    // 大额取款
    public event EventHandler<LargeWithdrawalArgs> LargeWithdrawalAlert;

    // 取款
    public void Withdraw(Account account, decimal amount)
    {
        try
        {
            // 客户改变主意10%概率
            Random random = new Random();
            if (random.Next(0, 100) < 10)
                throw new CustomerChangedMindException("Customer changed their mind. Transaction canceled.");

            // 模拟网络故障5%概率
            if (random.Next(0, 100) < 5)
                throw new NetworkFailureException("Network failure. Unable to complete transaction.");

            // 取款
            account.Withdraw(amount);

            // 触发大额取款
            if (amount > 10000)
                LargeWithdrawalAlert?.Invoke(this, new LargeWithdrawalArgs(account, amount));
        }
        catch (CustomerChangedMindException ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
        catch (NetworkFailureException ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

// 银行类
class Bank
{
    private List<Account> _accounts = new List<Account>();

    public void AddAccount(Account account)
    {
        _accounts.Add(account);
    }
    public Account FindAccount(string accountNumber)
    {
        return _accounts.Find(acc => acc.AccountNumber == accountNumber);
    }

    // 索引器
    public Account this[string accountNumber]
    {
        get
        {
            var account = _accounts.Find(acc => acc.AccountNumber == accountNumber);
            if (account == null)
                throw new KeyNotFoundException($"Account with number {accountNumber} not found.");
            return account;
        }
    }

    // 索引器
    public Account this[int index]
    {
        get
        {
            if (index < 0 || index >= _accounts.Count)
                throw new IndexOutOfRangeException("Index is out of range.");
            return _accounts[index];
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Bank bank = new Bank();

        SavingsAccount savingsAccount = new SavingsAccount("SAV-001", 15000);
        CheckingAccount checkingAccount = new CheckingAccount("CHK-001", 20000);

        bank.AddAccount(savingsAccount);
        bank.AddAccount(checkingAccount);
        ATM atm = new ATM();


        atm.LargeWithdrawalAlert += (sender, e) =>
        {
            Console.WriteLine($"Warning: Large amount of {e.Amount:C} withdrawn from account {e.Account.AccountNumber}.");
        };

        atm.Withdraw(savingsAccount, 2000);      // 正常取款
        atm.Withdraw(checkingAccount, 12000);    // 大额取款，触发事件
        atm.Withdraw(savingsAccount, 100000);    // 超过余额，抛出异常
        atm.Withdraw(checkingAccount, 3000);     // 模拟客户改变主意或网络故障

        try
        {
            Account acc1 = bank["SAV-001"];
            acc1.Deposit(500);

            Account acc2 = bank[1];
            acc2.Withdraw(1000);

            Account acc3 = bank["SAV-003"];
        }
        catch (KeyNotFoundException ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
        catch (IndexOutOfRangeException ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }

        Console.WriteLine("\nPress Enter to exit...");
        Console.ReadLine();
    }
}
